package com.example.demo.controllers.auth;

import com.example.demo.exception.CustomException;
import com.example.demo.exception.ErrorResponse;
import com.example.demo.model.dto.*;
import com.example.demo.model.entity.user.User;
import com.example.demo.model.enums.UserTypeEnum;
import com.example.demo.security.JwtTokenProvider;
import com.example.demo.service.AuthService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.CacheControl;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import org.springframework.security.core.GrantedAuthority;
import javax.validation.Valid;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@RestController
@RequestMapping("/api/auth")
@RequiredArgsConstructor
@Tag(name = "认证管理", description = "用户认证相关接口")
public class AuthController {

    private final AuthService authService;
    private final JwtTokenProvider jwtTokenProvider;
    // 存储已注销的令牌
    private static final Set<String> revokedTokens = new HashSet<>();

    @PostMapping("/login")
    @Operation(summary = "用户登录", description = "使用用户名和密码登录获取访问令牌")
    @ApiResponses({
            @ApiResponse(responseCode = "200", description = "登录成功",
                    content = @Content(schema = @Schema(implementation = AuthResponse.class))),
            @ApiResponse(responseCode = "400", description = "参数校验失败",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
            @ApiResponse(responseCode = "401", description = "用户名或密码错误",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
            @ApiResponse(responseCode = "403", description = "账户被禁用",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
    })
    public ResponseEntity<?> login(@Valid @RequestBody LoginDTO loginDTO, BindingResult bindingResult) {
        // 参数校验
        if (bindingResult.hasErrors()) {
            String errorMsg = bindingResult.getFieldErrors().stream()
                    .map(error -> error.getField() + ": " + error.getDefaultMessage())
                    .collect(Collectors.joining("; "));
            return ResponseEntity.badRequest()
                    .body(new ErrorResponse(400, "参数校验失败: " + errorMsg, "INVALID_PARAM"));
        }

        try {
            // 用户认证
            User user = authService.authenticateUser(loginDTO);

            // 账户状态检查
            if (!user.isAccountNonLocked()) {
                return ResponseEntity.status(HttpStatus.FORBIDDEN)
                        .body(new ErrorResponse(403, "账户已被禁用", "ACCOUNT_DISABLED"));
            }

            // 生成令牌
            String token = jwtTokenProvider.generateAccessToken(user);
            String refreshToken = jwtTokenProvider.generateRefreshToken(user);

            // 获取用户权限（基于userType）
            List<String> authorities = user.getAuthorities().stream()
                    .map(GrantedAuthority::getAuthority)
                    .collect(Collectors.toList());

            // 构造响应
            AuthResponse response = new AuthResponse(
                    token,
                    refreshToken,
                    UserDTO.fromEntity(user),
                    authorities);

            return ResponseEntity.ok(response);

        } catch (BadCredentialsException e) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
                    .body(new ErrorResponse(401, "用户名或密码错误", "AUTH_FAILED"));
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(new ErrorResponse(500, "系统错误: " + e.getMessage(), "SERVER_ERROR"));
        }
    }

    @PostMapping("/register")
    @Operation(summary = "用户注册", description = "注册新用户账号(管理员注册教师/教师注册学生)")
    @ApiResponses({
            @ApiResponse(responseCode = "200", description = "注册成功"),
            @ApiResponse(responseCode = "400", description = "参数校验失败",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
            @ApiResponse(responseCode = "403", description = "权限不足")
    })
    public ResponseEntity<?> register(
            @Valid @RequestBody RegisterDTO registerDTO,
            BindingResult bindingResult,
            @RequestHeader("Authorization") String authHeader) {

        // 参数校验失败处理
        if (bindingResult.hasErrors()) {
            String errorMessage = bindingResult.getFieldErrors().stream()
                    .map(error -> error.getField() + ": " + error.getDefaultMessage())
                    .collect(Collectors.joining("; "));

            return ResponseEntity.badRequest()
                    .body(new ErrorResponse(
                            HttpStatus.BAD_REQUEST.value(),
                            "参数校验失败 - " + errorMessage,
                            "VALIDATION_ERROR"));
        }

        // 获取当前用户角色
        User currentUser = authService.getCurrentUserFromToken(authHeader.substring(7));

        // 业务处理
        User registeredUser;
        if (currentUser.getUserType() == UserTypeEnum.ADMIN &&
                registerDTO.getRole() == UserTypeEnum.TEACHER) {
            // 管理员注册教师
            registeredUser = authService.registerTeacher(registerDTO);
        } else if (currentUser.getUserType() == UserTypeEnum.TEACHER &&
                registerDTO.getRole() == UserTypeEnum.STUDENT) {
            // 教师注册学生
            registeredUser = authService.registerStudent(registerDTO, currentUser.getUserId());
        } else {
            // 权限不足
            return ResponseEntity.status(HttpStatus.FORBIDDEN)
                    .body(new ErrorResponse(
                            HttpStatus.FORBIDDEN.value(),
                            "您没有权限注册此类型用户",
                            "PERMISSION_DENIED"));
        }

        return ResponseEntity.ok(registeredUser);
    }

    @PostMapping("/test-register")
    @Operation(summary = "测试用户注册", description = "仅用于后端测试，添加用户信息，无需验证")
    @ApiResponses({
            @ApiResponse(responseCode = "200", description = "注册成功"),
            @ApiResponse(responseCode = "400", description = "参数校验失败",
                    content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
    })
    public ResponseEntity<?> testRegister(
            @Valid @RequestBody RegisterDTO registerDTO,
            BindingResult bindingResult) {

        // 参数校验失败处理
        if (bindingResult.hasErrors()) {
            String errorMessage = bindingResult.getFieldErrors().stream()
                    .map(error -> error.getField() + ": " + error.getDefaultMessage())
                    .collect(Collectors.joining("; "));

            return ResponseEntity.badRequest()
                    .body(new ErrorResponse(
                            HttpStatus.BAD_REQUEST.value(),
                            "参数校验失败 - " + errorMessage,
                            "VALIDATION_ERROR"));
        }

        // 直接添加用户信息到数据库，不进行角色权限验证
        User registeredUser = authService.registerUser(registerDTO);

        return ResponseEntity.ok(registeredUser);
    }

    @PostMapping("/refresh")
    @Operation(summary = "刷新令牌", description = "使用刷新令牌获取新的访问令牌")
    public ResponseEntity<TokenDTO> refreshToken(@Valid @RequestBody TokenDTO tokenDTO) {
        // 验证refresh token有效性
        if (!jwtTokenProvider.isRefreshToken(tokenDTO.getRefreshToken())) {
            throw new IllegalArgumentException("提供的令牌不是有效的刷新令牌");
        }

        // 获取用户名
        String username = jwtTokenProvider.getUsernameFromToken(tokenDTO.getRefreshToken());

        // 生成新的access token
        User user = authService.getCurrentUser(username);
        String newToken = jwtTokenProvider.generateAccessToken(user);

        return ResponseEntity.ok(new TokenDTO(newToken, tokenDTO.getRefreshToken()));
    }

    @GetMapping("/me")/*参数为令牌*/
    @Operation(summary = "获取当前用户信息", description = "获取当前登录用户的详细信息")
    @ApiResponses({
            @ApiResponse(responseCode = "200", description = "成功获取用户信息"),
            @ApiResponse(responseCode = "401", description = "未授权/令牌无效"),
            @ApiResponse(responseCode = "403", description = "账号已被禁用"),
            @ApiResponse(responseCode = "404", description = "用户不存在")
    })
    public ResponseEntity<User> getCurrentUser(
            @RequestHeader(name = "Authorization", required = false) String authHeader) {

        // 1. 验证Authorization头是否存在
        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            throw new CustomException("缺少有效的认证令牌", HttpStatus.UNAUTHORIZED);
        }

        // 2. 提取并验证JWT令牌
        String jwt = authHeader.substring(7);
        if (!jwtTokenProvider.validateToken(jwt)) {
            throw new CustomException("无效的令牌", HttpStatus.UNAUTHORIZED);
        }

        try {
            // 3. 从令牌获取用户名
            String username = jwtTokenProvider.getUsernameFromToken(jwt);

            // 4. 获取用户信息
            User user = authService.getCurrentUser(username);

            // 5. 返回成功响应
            return ResponseEntity.ok()
                    .cacheControl(CacheControl.maxAge(30, TimeUnit.SECONDS))
                    .body(user);
        } catch (CustomException e) {
            // 6. 处理已知的业务异常
            throw e;
        } catch (Exception e) {
            // 7. 处理未知异常
            log.error("获取用户信息失败: {}", e.getMessage(), e);
            throw new CustomException("获取用户信息失败", HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    @PostMapping("/logout")
    @Operation(summary = "用户退出登录", description = "用户退出登录，将令牌加入黑名单")
    @ApiResponses({
            @ApiResponse(responseCode = "200", description = "退出登录成功"),
            @ApiResponse(responseCode = "401", description = "未授权/令牌无效")
    })
    public ResponseEntity<?> logout(@RequestHeader(name = "Authorization") String authHeader) {
        // 1. 验证Authorization头是否存在
        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            throw new CustomException("缺少有效的认证令牌", HttpStatus.UNAUTHORIZED);
        }

        // 2. 提取 JWT 令牌
        String jwt = authHeader.substring(7);

        // 3. 验证令牌有效性
        if (!jwtTokenProvider.validateToken(jwt)) {
            throw new CustomException("无效的令牌", HttpStatus.UNAUTHORIZED);
        }

        // 4. 将令牌加入黑名单
        revokedTokens.add(jwt);


        return ResponseEntity.ok(Collections.singletonMap("message", "退出登录成功"));
    }

}